"""Jenkins API服务"""
import requests
from typing import List, Dict, Any
from datetime import datetime
from mysql.connector import Error
from concurrent.futures import ThreadPoolExecutor, as_completed
from config.jenkins_config import JENKINS_CONFIG
from config.db_config import DB_CONFIG, JENKINS_DB_CONFIG
import mysql.connector
from utils.logger import sync_logger

class JenkinsService:
    def __init__(self, db_config=None):
        self.config = JENKINS_CONFIG
        self.db_config = db_config or JENKINS_DB_CONFIG
    
    def get_db_connection(self):
        """获取数据库连接"""
        return mysql.connector.connect(**self.db_config)
    
    def init_jenkins_table(self):
        """自动建表，确保jenkins_builds表存在"""
        with sync_logger.start_timer("创建/检查Jenkins构建表"):
            try:
                conn = self.get_db_connection()
                cursor = conn.cursor()
                cursor.execute('''
                    CREATE TABLE IF NOT EXISTS jenkins_builds (
                        id INT AUTO_INCREMENT PRIMARY KEY,
                        job_name VARCHAR(255) NOT NULL COMMENT 'Jenkins任务名称',
                        build_number INT NOT NULL COMMENT '构建编号',
                        status VARCHAR(50) COMMENT '构建状态',
                        duration INT COMMENT '构建耗时（秒）',
                        timestamp DATETIME COMMENT '构建开始时间',
                        git_commit VARCHAR(255) COMMENT '关联的Git提交ID',
                        triggered_by VARCHAR(255) COMMENT '触发人/触发方式',
                        parameters TEXT COMMENT '构建参数',
                        console_log_url VARCHAR(255) COMMENT '日志链接',
                        UNIQUE KEY unique_job_build (job_name, build_number)
                    ) COMMENT='Jenkins构建记录表';
                ''')
                conn.commit()
                cursor.close()
                conn.close()
                sync_logger.log_info("jenkins_builds表检查/创建完成")
            except Error as e:
                sync_logger.log_error(f"建表失败: {e}")
    
    def get_jenkins_jobs(self) -> List[str]:
        """获取所有Jenkins任务名称"""
        with sync_logger.start_timer("获取Jenkins任务列表"):
            url = f"{self.config['url']}/api/json"
            try:
                resp = requests.get(
                    url, 
                    auth=(self.config['user'], self.config['token']), 
                    timeout=self.config['timeout']
                )
                jobs = resp.json().get('jobs', [])
                job_names = [job['name'] for job in jobs]
                sync_logger.log_info(f"共获取到 {len(job_names)} 个Jenkins任务")
                return job_names
            except Exception as e:
                sync_logger.log_error(f"获取Jenkins任务列表失败: {e}")
                return []
    
    def get_job_builds(self, job_name: str) -> List[int]:
        """获取指定任务的所有构建编号"""
        url = f"{self.config['url']}/job/{job_name}/api/json?tree=builds[number]"
        try:
            resp = requests.get(
                url, 
                auth=(self.config['user'], self.config['token']), 
                timeout=self.config['timeout']
            )
            builds = resp.json().get('builds', [])
            build_numbers = [b['number'] for b in builds]
            sync_logger.log_info(f"任务 {job_name} 共获取到 {len(build_numbers)} 个构建")
            return build_numbers
        except Exception as e:
            sync_logger.log_error(f"获取任务{job_name}的构建列表失败: {e}")
            return []
    
    def get_build_info(self, job_name: str, build_number: int) -> Dict[str, Any]:
        """获取单次构建的详细信息"""
        url = f"{self.config['url']}/job/{job_name}/{build_number}/api/json"
        try:
            resp = requests.get(
                url, 
                auth=(self.config['user'], self.config['token']), 
                timeout=self.config['timeout']
            )
            data = resp.json()
            # 解析关键信息
            build_info = {
                'job_name': job_name,
                'build_number': build_number,
                'status': data.get('result'),
                'duration': int(data.get('duration', 0)) // 1000,  # ms转秒
                'timestamp': datetime.fromtimestamp(data.get('timestamp', 0)/1000) if data.get('timestamp') else None,
                'git_commit': '',
                'triggered_by': '',
                'parameters': '',
                'console_log_url': f"{self.config['url']}/job/{job_name}/{build_number}/console"
            }
            # 获取Git提交ID
            actions = data.get('actions', [])
            for act in actions:
                if 'lastBuiltRevision' in act:
                    build_info['git_commit'] = act['lastBuiltRevision'].get('SHA1', '')
                if 'causes' in act:
                    causes = act['causes']
                    if causes:
                        build_info['triggered_by'] = causes[0].get('userName', causes[0].get('_class', ''))
                if 'parameters' in act:
                    build_info['parameters'] = str(act['parameters'])
            return build_info
        except Exception as e:
            sync_logger.log_error(f"获取构建{job_name}#{build_number}信息失败: {e}")
            return {}
    
    def save_build_to_db(self, build: Dict[str, Any]):
        """保存单条构建数据到数据库"""
        try:
            conn = self.get_db_connection()
            cursor = conn.cursor()
            sql = '''
                INSERT INTO jenkins_builds (
                    job_name, build_number, status, duration, timestamp, git_commit, triggered_by, parameters, console_log_url
                ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
                ON DUPLICATE KEY UPDATE
                    status=VALUES(status),
                    duration=VALUES(duration),
                    timestamp=VALUES(timestamp),
                    git_commit=VALUES(git_commit),
                    triggered_by=VALUES(triggered_by),
                    parameters=VALUES(parameters),
                    console_log_url=VALUES(console_log_url)
            '''
            values = (
                build['job_name'], build['build_number'], build['status'], build['duration'],
                build['timestamp'], build['git_commit'], build['triggered_by'], build['parameters'], build['console_log_url']
            )
            cursor.execute(sql, values)
            conn.commit()
            cursor.close()
            conn.close()
            sync_logger.log_info(f"构建数据已保存: {build['job_name']}#{build['build_number']}")
        except Error as e:
            sync_logger.log_error(f"保存构建数据失败: {e}")
    
    def process_build(self, job, build_number):
        """单个构建的采集和上传流程，适用于多线程"""
        build_info = self.get_build_info(job, build_number)
        if build_info:
            self.save_build_to_db(build_info)
    
    def sync_jenkins_builds(self):
        """主同步流程：多线程采集所有Jenkins任务的构建数据并上传"""
        with sync_logger.start_timer("Jenkins数据同步"):
            sync_logger.log_info("开始同步Jenkins数据...")
            self.init_jenkins_table()
            jobs = self.get_jenkins_jobs()
            max_workers = 8  # 可根据机器性能调整
            tasks = []
            
            with ThreadPoolExecutor(max_workers=max_workers) as executor:
                for job in jobs:
                    build_numbers = self.get_job_builds(job)
                    for build_number in build_numbers:
                        tasks.append(executor.submit(self.process_build, job, build_number))
                
                for future in as_completed(tasks):
                    future.result()  # 捕获异常
            
            sync_logger.log_info("Jenkins数据同步完成！") 